﻿using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using Wicture.DbRESTFul.SQL;
using Wicture.EPC.Common;
using Wicture.EPC.Service.V1.Models;
using Wicture.EPC.Service.V1.Repository;

namespace Wicture.EPC.Service.V1.QueryInterceptors.Interceptors
{
    public class MazdaQueryInterceptor : BaseQueryInterceptor
    {
        public override string[] BrandCodes { get; } = new string[] { "mazda", "mazda_yq" };

        public override object QueryHotPoints(DbRESTFulRepository repository, JObject param)
        {
            IEnumerable<dynamic> data = repository.Invoke(CSIs.Query_HotPoints_For_Mazda, param);
            if (data.Count() == 0) return null;
            return new
            {
                imgs = new List<Query_HotPointsResult._imgs> {
                    new Query_HotPointsResult._imgs {
                        url =data.FirstOrDefault().url,
                        points =JArray.FromObject(data).ToObject<List<Query_HotPointsResult._imgs._points>>()
                    }
                }
            };
        }

        public override object QueryPartDetail(DbRESTFulRepository repository, JObject param)
        {
            param.RemoveEmptyValues();
            var brandCode = param.Value<string>(ParamFields._brandCode);
            var partId = param.Value<string>(ParamFields._partId);
            dynamic data = null;
            if (string.IsNullOrEmpty(partId))
            {
                data = repository.Invoke(CSIs.Get_Part_Detail_Standard, param);
            }
            else
            {
                data = repository.Invoke(CSIs.Get_Usage_Detail_Standard, param);
            }
            if (data == null) return null;
            Query_Part_DetailResult result = JObject.FromObject(data).ToObject<Query_Part_DetailResult>();

            //3.替换件处理
            if (result.replacementPartNo != null)
            {
                List<Query_Part_DetailResult._replacement> replacements = repository.Invoke<Query_Part_DetailResult._replacement>(CSIs.Query_Parts_By_Codes, new { partCodes = result.replacementPartNo.Split(',') });
                var replacement = replacements.FirstOrDefault();
                if (replacement != null)
                {
                    replacement.brandCode = brandCode;
                    replacement.brandName = BrandDictionary.GetName(brandCode);
                    result.replacements = new List<Query_Part_DetailResult._replacement>();
                    result.replacements.Add(replacement);
                }
            }

            //4.配件附加属性处理
            var props = new List<Query_Part_DetailResult._prop>
            {
                new Query_Part_DetailResult._prop { key = "件数", value = result.quantity ?? string.Empty },
                new Query_Part_DetailResult._prop { key = "备注", value = data.notes ?? string.Empty }
            };
            result.props = props.Where(q => !string.IsNullOrEmpty(q.value)).ToList();
            return result;
        }
        protected override IEnumerable<Query_SubGroupResult> GetSubGroup(DbRESTFulRepository repository, JObject param)
        {
            return repository.Invoke<Query_SubGroupResult>(CSIs.Query_SubGroup_For_Mazda, param);
        }

        private List<string> GetFeatureListFromStr(string featureStr, string addFeatureStr = "")
        {
            List<string> retList = new List<string>();
            if (string.IsNullOrEmpty(featureStr) && string.IsNullOrEmpty(addFeatureStr))
            {
                return retList;
            }
            if (!string.IsNullOrEmpty(featureStr))
            {
                for (int i = 0; i < featureStr.Length; i = i + 6)
                {
                    int len = 6;
                    if (featureStr.Length - i < 6)
                    {
                        len = featureStr.Length - i;
                    }
                    retList.Add(featureStr.Substring(i, len).Trim());
                }
            }
            if (!string.IsNullOrEmpty(addFeatureStr))
            {
                for (int i = 0; i < addFeatureStr.Length; i = i + 6)
                {
                    int len = 6;
                    if (addFeatureStr.Length - i < 6)
                    {
                        len = addFeatureStr.Length - i;
                    }
                    retList.Add(addFeatureStr.Substring(i, len).Trim());
                }
            }
            return retList;
        }
        protected override List<Query_SubGroupResult> FilterSubGroupsByVin(DbRESTFulRepository repository, List<Query_SubGroupResult> results, JObject param)
        {
            var vin = param.Value<string>(ParamFields._vin);
            if (string.IsNullOrEmpty(vin) || results == null || results.Count == 0)
            {
                return results;
            }
            var vinInfo = QueryVinByCode(repository, new Get_Model_InfoParam { vin = vin });
            if (vinInfo == null) return results;
            string featureCodes = vinInfo.featureCodes;
            string addFeatureCodes = vinInfo.addFeatureCodes;
            int? productionDate = vinInfo.productionDate;
            var vinFeatureDic = GetFeatureListFromStr(featureCodes, addFeatureCodes).GroupBy(q => q.Substring(0, 3)).ToDictionary(k => k.Key, v => v.ToHashSet());

            foreach (var result in results)
            {
                if (!MatchFeatures(vinFeatureDic, result.subgroupFilterCode))
                {
                    result.belongTo = false;
                    continue;
                }
                if (!MatchProductionDate(productionDate, result.startTime, result.endTime))
                {
                    result.belongTo = false;
                    continue;
                }
                if (!MatchFeatures(vinFeatureDic, result.specCodes))
                {
                    result.belongTo = false;
                    continue;
                }
            }
            return results;
        }

        private bool MatchProductionDate(int? productionDate, int? startTime, int? endTime)
        {
            if (!productionDate.HasValue && productionDate == 0) return true;
            if (!startTime.HasValue) startTime = 0;
            if (startTime > productionDate)
            {
                return false;
            }
            if (!endTime.HasValue) endTime = 99999999;
            if (endTime < productionDate)
            {
                return false;
            }
            return true;
        }

        private bool MatchFeatures(Dictionary<string, HashSet<string>> vinFeatureDic, string features)
        {
            if (string.IsNullOrEmpty(features)) return true;
            var list = GetFeatureListFromStr(features);
            foreach(var info in list)
            {
                var family = info.Substring(0, 3);
                if(!vinFeatureDic.ContainsKey(family))
                {
                    continue;
                }
                if(!vinFeatureDic[family].Contains(info))
                {
                    return false;
                }
            }
            return true;
        }
        protected override List<Query_SubGroupResult> BuildSubGroupResults(List<Query_SubGroupResult> result)
        {
            return result.GroupBy(q => q.imageSN).Select(q => new Query_SubGroupResult
            {
                id = q.First().id,
                code = q.First().code,
                belongTo = q.Any(x => x.belongTo),
                imageUrl = q.First().imageUrl,
                imageSN = q.Key,
                mainGroupCode = q.First().mainGroupCode,
                name = q.First().name,
                mainGroupId = q.First().mainGroupId,
                remark = q.First().remark
            }).ToList();
        }

        protected override List<Query_PartsResult> GetParts(DbRESTFulRepository repository, JObject param)
        {
            return repository.Invoke<Query_PartsResult>(CSIs.Query_Parts_For_Mazda, param);
        }

        protected override List<Query_PartsResult> BuildPartResults(List<Query_PartsResult> results)
        {
            foreach (var info in results)
            {
                if (!string.IsNullOrEmpty(info.replacedPartCodes))
                {
                    info.modelNotes = $"替换为{info.replacedPartCodes}";
                }
            }
            return results.GroupBy(q => new { q.imageSN, q.partCode, q.quantity, q.modelNotes, q.notes }).Select(q => new Query_PartsResult
            {
                id = q.First().id,
                imageSN = q.Key.imageSN,
                partCode = q.Key.partCode,
                partName = (q.First().partName + " " + string.Join(" ", q.Select(x => x.trimColor).Distinct().OrderBy(y => y))).Trim(),
                quantity = q.Key.quantity,
                modelNotes = q.Key.modelNotes,
                notes = q.Key.notes,
                replacedPartCodes = q.First().replacedPartCodes,
                cost = q.First().cost,
                price = q.First().price,
                priceUpdatedAt = q.First().priceUpdatedAt,
                belongToVin = q.Any(x => x.belongToVin),
                brandCode = q.First().brandCode,
                brandName = q.First().brandName
            }).ToList();
        }

        protected override void FilterPartsByVin(DbRESTFulRepository repository, ref List<Query_PartsResult> results, string vin, string selectorId)
        {
            if (!string.IsNullOrEmpty(vin))
            {
                var vinInfo = QueryVinByCode(repository, new Get_Model_InfoParam { vin = vin });
                if (vinInfo != null)
                {
                    string featureCodes = vinInfo.featureCodes;
                    string addFeatureCodes = vinInfo.addFeatureCodes;
                    int? productionDate = vinInfo.productionDate;
                    string trimColor = vinInfo.trimColor;
                    string bodyColor = vinInfo.bodyColor;
                    var vinFeatureDic = GetFeatureListFromStr(featureCodes, addFeatureCodes).GroupBy(q => q.Substring(0, 3)).ToDictionary(k => k.Key, v => v.ToHashSet());

                    foreach (var result in results)
                    {
                        if (!MatchProductionDate(productionDate, result.startTime, result.endTime))
                        {
                            result.belongToVin = false;
                            continue;
                        }
                        if (!MatchProductionDate(productionDate, result.partStartTime, result.partEndTime))
                        {
                            result.belongToVin = false;
                            continue;
                        }
                        if (!MatchFeatures(vinFeatureDic, result.featureCodes))
                        {
                            result.belongToVin = false;
                            continue;
                        }
                        if (!string.IsNullOrEmpty(result.trimColor) && result.trimColor != trimColor && result.trimColor != bodyColor)
                        {
                            result.belongToVin = false;
                            continue;
                        }
                    }
                }
            }

            List<SubGroupInfo> allGroups = null;
            foreach (var result in results)
            {
                if (!string.IsNullOrEmpty(result.imageSN) && string.IsNullOrEmpty(result.partCode))
                {
                    if (allGroups == null)
                    {
                        allGroups = repository.Invoke<SubGroupInfo>(CSIs.Query_All_Group_By_SelectorId, new { selectorId });
                    }
                    var subGroupInfo = allGroups.Where(q => q.subGroupCode.StartsWith(result.imageSN)).FirstOrDefault();
                    if (subGroupInfo != null)
                    {
                        result.notes = $"参见：<a data='mainGroupId={subGroupInfo.mainGroupId},subGroupId={subGroupInfo.id}'>{result.imageSN}</a>";
                    }
                }
            }
        }

        protected override IEnumerable<dynamic> GetHotPoints(DbRESTFulRepository repository, JObject param)
        {
            return repository.Invoke(CSIs.Query_HotPoints_For_Mazda, param);
        }

        protected override dynamic QueryVinByCode(DbRESTFulRepository repository, Get_Model_InfoParam param)
        {
            return repository.Invoke(CSIs.Query_Vin_By_Code_For_Mazda, param);
        }
        protected override List<Get_Model_InfoResult._props> GetVinProps(DbRESTFulRepository repository, dynamic vin)
        {
            List<Get_Model_InfoResult._props> props = new List<Get_Model_InfoResult._props>();
            props.Add(new Get_Model_InfoResult._props { key = "车型", value = vin.name });
            props.Add(new Get_Model_InfoResult._props { key = "年款", value = vin.modelYear?.ToString() });
            props.Add(new Get_Model_InfoResult._props { key = "生产日期", value = vin.productionDate?.ToString() });
            props.Add(new Get_Model_InfoResult._props { key = "MSC", value = vin.MSC });
            props.Add(new Get_Model_InfoResult._props { key = "车身颜色", value = vin.bodyColor });
            props.Add(new Get_Model_InfoResult._props { key = "内部颜色", value = vin.trimColor });
            props.Add(new Get_Model_InfoResult._props { key = "目录号", value = vin.code });
            return props.Where(q => !string.IsNullOrEmpty(q.value)).ToList();
        }
        protected override List<Get_Model_InfoResult._features> GetVinFeatures(DbRESTFulRepository repository, dynamic vin)
        {
            string featureCodes = vin.featureCodes;
            if (!string.IsNullOrEmpty(featureCodes))
            {
                List<Get_Model_InfoResult._features> retList = new List<Get_Model_InfoResult._features>();
                var featureCodeList = GetFeatureListFromStr(featureCodes);
                IEnumerable<Feature> features = repository.Invoke<Feature>(CSIs.Query_Vin_Features_For_Mazda, new { modelCode = vin.code, featureCodes = featureCodeList });
                foreach (var feature in features)
                {
                    retList.Add(new Get_Model_InfoResult._features() { key = feature.featureCode, value = feature.featureName });
                }
                return retList;
            }
            else
            {
                return null;
            }
        }

        protected override dynamic GetModelsByPart(DbRESTFulRepository repository, int pageIndex, int pageSize, string brandCode, string partCode)
        {
            return repository.Invoke(CSIs.Query_Models_By_Part_For_Mazda, new { pageIndex, pageSize, brandCode, partCode });
        }

        protected override dynamic GetHotPointsByPart(DbRESTFulRepository repository, string brandCode, string partCode, IEnumerable<string> imageIds)
        {
            return repository.Invoke(CSIs.Query_HotPoints_By_Part_For_Mazda, new { brandCode, partCode, imageIds });
        }

        protected override List<SearchSubGroupResults> GetSearchResults(DbRESTFulRepository repository, string brandCode, string[] partCodes, string selectorId)
        {
            return repository.Invoke<SearchSubGroupResults>(CSIs.Search_SubGroups_By_PartCodes_For_Mazda, new { brandCode, partCodes, selectorId });
        }

        protected override List<QuickPartResult> QuickQueryPartsFilterByUsage_Model(DbRESTFulRepository repository, List<QuickPartResult> parts, int selectorId)
        {
            List<QuickPartResult> ret = new List<QuickPartResult>();
            if (selectorId > 0 && parts != null && parts.Any())
            {
                List<string> partCodes = parts.Select(e => e.partCode).Distinct().ToList();

                List<Query_PartsResult> partUsages = repository.Invoke<Query_PartsResult>(CSIs.Quick_PartUsage_By_SelectorId_For_Mazda, new { selectorId, partCodes });
                if (partUsages != null && partUsages.Any())
                {
                    foreach (var item in parts)
                    {
                        if (partUsages.FirstOrDefault(e => e.partCode == item.partCode) != null)
                        {
                            ret.Add(item);
                        }
                    }
                }
            }
            return ret;
        }

        protected override List<QuickPartResult> QuickQueryPartsFilterByUsage_Vin(DbRESTFulRepository repository, List<QuickPartResult> parts, int selectorId, string vin)
        {
            List<QuickPartResult> ret = new List<QuickPartResult>();
            if (!string.IsNullOrEmpty(vin) && parts != null && parts.Any())
            {
                List<string> partCodes = parts.Select(e => e.partCode).Distinct().ToList();
                List<Query_PartsResult> partUsages = repository.Invoke<Query_PartsResult>(CSIs.Quick_PartUsage_For_Mazda, new { selectorId, partCodes });
                if (partUsages != null && partUsages.Any())
                {
                    List<string> usedPartCodes = new List<string>();

                    HashSet<string> setCodes = new HashSet<string>();
                    dynamic vinInfo = repository.Invoke(CSIs.Query_Quick_Vin_For_Mazda, new { vin });

                    if (vinInfo != null)
                    {
                        string featureCodes = vinInfo.featureCodes;
                        string addFeatureCodes = vinInfo.addFeatureCodes;
                        int? productionDate = vinInfo.productionDate;
                        string trimColor = vinInfo.trimColor;
                        string bodyColor = vinInfo.bodyColor;
                        var vinFeatureDic = GetFeatureListFromStr(featureCodes, addFeatureCodes).GroupBy(q => q.Substring(0, 3)).ToDictionary(k => k.Key, v => v.ToHashSet());

                        foreach (var item in partUsages)
                        {
                            if (!MatchProductionDate(productionDate, item.startTime, item.endTime))
                            {
                                continue;
                            }
                            if (!MatchProductionDate(productionDate, item.partStartTime, item.partEndTime))
                            {
                                continue;
                            }
                            if (!MatchFeatures(vinFeatureDic, item.featureCodes))
                            {
                                continue;
                            }
                            if (!string.IsNullOrEmpty(item.trimColor) && item.trimColor != trimColor && item.trimColor != bodyColor)
                            {
                                continue;
                            }
                            usedPartCodes.Add(item.partCode);
                        }
                    }

                    if (usedPartCodes.Any())
                    {
                        ret = parts.Where(e => usedPartCodes.Contains(e.partCode)).ToList();
                    }
                }
            }
            return ret;
        }
    }
}
